www.gusucode.com > VC++ 人脸识别定位、眼睛、嘴巴和鼻识别-源码程序 > VC++ 人脸识别定位、眼睛、嘴巴和鼻识别-源码程序/code/人脸定位实例/FaceDetectDlg.cpp

    //Download by http://www.NewXing.com
// FaceDetectDlg.cpp : implementation file
//

#include "stdafx.h"
#include "FaceDetect.h"
#include "FaceDetectDlg.h"
#include "ReplaceDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#include "AddSampleDlg.h"

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CFaceDetectDlg dialog

CFaceDetectDlg::CFaceDetectDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CFaceDetectDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CFaceDetectDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CFaceDetectDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CFaceDetectDlg)
		// NOTE: the ClassWizard will add DDX and DDV calls here
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CFaceDetectDlg, CDialog)
	//{{AFX_MSG_MAP(CFaceDetectDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BTN_BINARY, OnBtnBinary)
	ON_BN_CLICKED(IDC_BTN_EDGE, OnBtnEdge)
	ON_BN_CLICKED(IDC_BTN_FACEHAIR, OnBtnFacehair)
	ON_BN_CLICKED(IDC_BTN_HISTOGRAM_FACE, OnBtnHistogramFace)
	ON_BN_CLICKED(IDC_BTN_HISTOGRAM_H, OnBtnHistogramH)
	ON_BN_CLICKED(IDC_BTN_HISTOGRAM_HAIR, OnBtnHistogramHair)
	ON_BN_CLICKED(IDC_BTN_HISTOGRAM_V, OnBtnHistogramV)
	ON_BN_CLICKED(IDC_BTN_LIKEHOOD, OnBtnLikehood)
	ON_BN_CLICKED(IDC_BTN_MARK_EYE, OnBtnMarkEye)
	ON_BN_CLICKED(IDC_BTN_MARK_FACE_1, OnBtnMarkFace1)
	ON_BN_CLICKED(IDC_BTN_MARK_FACE_2, OnBtnMarkFace2)
	ON_BN_CLICKED(IDC_BTN_MARK_MOUSE, OnBtnMarkMouse)
	ON_BN_CLICKED(IDC_BTN_MARK_NOSE, OnBtnMarkNose)
	ON_BN_CLICKED(IDC_BTN_OPENFILE, OnBtnOpenfile)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CFaceDetectDlg message handlers

BOOL CFaceDetectDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	CWnd *pWnd0= GetDlgItem(IDC_BMPSHOW);
	pDCShow = pWnd0->GetDC();

	m_pMainDib = new CDib();

	m_tOriPixelArray = NULL;
	m_tResPixelArray = NULL;

	m_pResMap = NULL;

	m_nWndWidth = 0;
	m_nWndHeight= 0;
	m_sFileName = "";

	m_bSelectByMan = false;
	m_bLBottonDown = false;

	m_ManLeft = -1;
	m_ManRight = -1;
	m_ManTop = -1;
	m_ManBottom = -1;

	m_bFaceOK = false;
	m_bShowFace = false;
	m_rFaceRegion.left = m_rFaceRegion.right = m_rFaceRegion.top = m_rFaceRegion.bottom = 0;

	m_bManualMarkFacial = false;
	m_bLeftEyeOK = m_bRightEyeOK = m_bLeftNostrilOK = m_bRightNostrilOK =
	m_bLeftEyeLeftCornerOK = m_bLeftEyeRightCornerOK = m_bRightEyeLeftCornerOK = 
	m_bRightEyeRightCornerOK = m_bLeftMouthCornerOK = m_bRightMouthCornerOK = false;

	m_bMidMouthOK = m_bMidNoseOK = false;

	m_LeftEye = m_RightEye = m_LeftEyeLeftCorner = m_LeftEyeRightCorner = 
	m_LeftNostril = m_RightNostril = m_RightEyeLeftCorner = m_RightEyeRightCorner =
	m_LeftMouthCorner = m_RightMouthCorner = m_MidMouth = m_MidNose = CPoint(-1,-1);
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CFaceDetectDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CFaceDetectDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);

		if(m_tResPixelArray==NULL) return;
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CFaceDetectDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

////////////////////////////////////////////////////////////////////////////////
// 画十字形标记
// 参数:  pDC-CDC指针
//         point-要画的点的坐标
//         crColor-标记得颜色
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::DrawCross(CDC *pDC, CPoint point, COLORREF crColor)
{
	CPen pen,*oldPen;
	pen.CreatePen(PS_SOLID,1,crColor);
	oldPen = (CPen*)pDC->SelectObject(&pen);
	pDC->MoveTo(point.x-7,point.y);
	pDC->LineTo(point.x+7,point.y);
	pDC->MoveTo(point.x,point.y-7);
	pDC->LineTo(point.x,point.y+7);
	pDC->SelectObject(oldPen);
	pen.DeleteObject();
}

////////////////////////////////////////////////////////////////////////////////
// 拷贝位图
// 参数:  dest-目标位图指针
//         source-源位图指针
////////////////////////////////////////////////////////////////////////////////
bool CFaceDetectDlg::CopyBitMap(RGBQUAD **dest, RGBQUAD **source)
{
	if(source==NULL || dest==NULL) 
		return false;
	for(int i=0; i<m_nWndHeight; i++)
		for(int j=0; j<m_nWndWidth; j++)
			dest[i][j]=source[i][j];
	
	return true;
}

////////////////////////////////////////////////////////////////////////////////
// 生成新的位图
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::MakeBitMap()
{
	CClientDC ClientDC(pDCShow->GetWindow());
	if(m_pResMap!=NULL) delete m_pResMap;

	m_pResMap=new CBitmap();
	m_pResMap->CreateCompatibleBitmap(&ClientDC,m_nWndWidth,m_nWndHeight);

	CDC  dc;
	dc.CreateCompatibleDC(&ClientDC);
	dc.SelectObject(m_pResMap);

	for(int i=0; i<m_nWndHeight; i++)
	for(int j=0; j<m_nWndWidth; j++)
	dc.SetPixelV(j,i,RGB(m_tResPixelArray[i][j].rgbRed,m_tResPixelArray[i][j].rgbGreen,m_tResPixelArray[i][j].rgbBlue));

	if(m_bFaceOK && m_bShowFace)
	{
		CBrush Pen;
		Pen.CreateSolidBrush(RGB(255,0,0));
		dc.FrameRect(m_rFaceRegion,&Pen);
	 	Pen.DeleteObject();
	}

	if(m_bLeftEyeOK)					DrawCross(&dc,m_LeftEye,RGB(255,0,0));
	if(m_bRightEyeOK)					DrawCross(&dc,m_RightEye,RGB(255,0,0));
	if(m_bLeftEyeLeftCornerOK)			DrawCross(&dc,m_LeftEyeLeftCorner,RGB(255,0,255));
	if(m_bLeftEyeRightCornerOK)			DrawCross(&dc,m_LeftEyeRightCorner,RGB(255,255,0));
	if(m_bRightEyeLeftCornerOK)			DrawCross(&dc,m_RightEyeLeftCorner,RGB(255,0,255));
	if(m_bRightEyeRightCornerOK)		DrawCross(&dc,m_RightEyeRightCorner,RGB(255,255,0));
	if(m_bLeftNostrilOK)				DrawCross(&dc,m_LeftNostril,RGB(0,255,0));
	if(m_bRightNostrilOK)				DrawCross(&dc,m_RightNostril,RGB(0,255,0));
	if(m_bMidNoseOK)					DrawCross(&dc,m_MidNose,RGB(0,255,0));
	if(m_bLeftMouthCornerOK)			DrawCross(&dc,m_LeftMouthCorner,RGB(0,0,255));
	if(m_bRightMouthCornerOK)			DrawCross(&dc,m_RightMouthCorner,RGB(0,0,255));
	if(m_bMidMouthOK)					DrawCross(&dc,m_MidMouth,RGB(0,0,255));

	dc.DeleteDC();

	MyDraw();
}

////////////////////////////////////////////////////////////////////////////////////
//读原图的数据
////////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::LoadOriPixel(CDib *pDib)
{
	BYTE	*colorTable;
	colorTable = (BYTE *)pDib->m_pDibBits;
	int byteBitCount  = pDib->GetBiBitCount()/8;

	m_tOriPixelArray  = new RGBQUAD*[m_nWndHeight];
	m_tResPixelArray  = new RGBQUAD*[m_nWndHeight];
	for(int l=0 ; l<m_nWndHeight; l++)
	{
		m_tOriPixelArray[l] = new RGBQUAD[m_nWndWidth];
		m_tResPixelArray[l] = new RGBQUAD[m_nWndWidth];
	}

	int count = 0;
	for(int i=m_nWndHeight-1; i>=0; i--)
	{
		for(int j=0; j<m_nWndWidth; j++)
		{
			m_tOriPixelArray[i][j].rgbBlue =colorTable[count++];
			m_tOriPixelArray[i][j].rgbGreen=colorTable[count++];
			m_tOriPixelArray[i][j].rgbRed  =colorTable[count++];
			m_tOriPixelArray[i][j].rgbReserved = 0;
			m_tResPixelArray[i][j]=m_tOriPixelArray[i][j];
			count += byteBitCount-3;
		}
		count += (4-(m_nWndWidth*byteBitCount)%4)%4;
	}

	method1 = new CLikelyHood(m_tOriPixelArray,m_nWndWidth,m_nWndHeight);
	method2 = new CHairFace(m_tOriPixelArray,m_nWndWidth,m_nWndHeight);
}

////////////////////////////////////////////////////////////////////////////////
// 给位图赋值
// 参数:  target-目标位图指针
//         Val-要赋予的值
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::SetPixelArray(RGBQUAD **target, int Val)
{
	for(int i=0; i<m_nWndHeight; i++)
	for(int j=0; j<m_nWndWidth; j++)
	{
		target[i][j].rgbRed =  target[i][j].rgbBlue = target[i][j].rgbGreen = Val;
	}
}

////////////////////////////////////////////////////////////////////////////////
// 边界检测
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::DoLOG(int left, int right, int top, int bottom, RGBQUAD **source, RGBQUAD **target)
{
	int i,j;

	double **result;					 
	result = new double*[m_nWndHeight];
	for(int l=0 ; l<m_nWndHeight; l++)
	{
		result[l] = new double[m_nWndWidth];
		for(j=0; j<m_nWndWidth; j++)
			result[l][j] = source[l][j].rgbRed;
	}
	
	for(i=0; i<m_nWndHeight; i++)
	for(j=0; j<m_nWndWidth; j++)
	{
		double r,g,temp;
		temp = source[i][j].rgbGreen+source[i][j].rgbRed+source[i][j].rgbBlue;
		r = (double)source[i][j].rgbRed/temp;
		g = (double)source[i][j].rgbGreen/temp;
		if(g<0.398 && g > 0.246 && r<0.664 && r>0.233 && r>g && g>=0.5*(1-r))
		{
			target[i][j].rgbRed = 255;  //face
		}
		else target[i][j].rgbRed = 0;
	}
	
	for(i=top+2; i<bottom-2; i++)
	for(j=left+2; j<right-2; j++)
	{
		result[i][j] =  
			     (0-2.0/24.0)*((unsigned char)target[i-2][j-2].rgbRed) + 
                 (0-4.0/24.0)*((unsigned char)target[i-2][j-1].rgbRed) + 
			     (0-4.0/24.0)*((unsigned char)target[i-2][j].rgbRed)   +
			     (0-4.0/24.0)*((unsigned char)target[i-2][j+1].rgbRed) +
			     (0-2.0/24.0)*((unsigned char)target[i-2][j+2].rgbRed) +
				 (0-4.0/24.0)*((unsigned char)target[i-1][j-2].rgbRed) + 
				 (8.0/24.0)  *((unsigned char)target[i-1][j].rgbRed)   +
				 (0-4.0/24.0)*((unsigned char)target[i-1][j+2].rgbRed) +
				 (0-4.0/24.0)*((unsigned char)target[i][j-2].rgbRed)   + 
				 (8.0/24.0)  *((unsigned char)target[i][j-1].rgbRed)   + 
				 (1.0)       *((unsigned char)target[i][j].rgbRed)     +
				 (8.0/24.0)  *((unsigned char)target[i][j+1].rgbRed)   +
				 (0-4.0/24.0)*((unsigned char)target[i][j+2].rgbRed)   +
				 (0-4.0/24.0)*((unsigned char)target[i+1][j-2].rgbRed) + 
				 (8.0/24.0)  *((unsigned char)target[i+1][j].rgbRed)   +
				 (0-4.0/24.0)*((unsigned char)target[i+1][j+2].rgbRed) +
				 (0-2.0/24.0)*((unsigned char)target[i+2][j-2].rgbRed) + 
				 (0-4.0/24.0)*((unsigned char)target[i+2][j-1].rgbRed) + 
				 (0-4.0/24.0)*((unsigned char)target[i+2][j].rgbRed)   +
				 (0-4.0/24.0)*((unsigned char)target[i+2][j+1].rgbRed) +
				 (0-2.0/24.0)*((unsigned char)target[i+2][j+2].rgbRed);
	}

	SetPixelArray(target,255);

	for(i=top+1; i<bottom-1; i++)
	for(j=left+1; j<right-1; j++)
	{
		int positive = 0;   
		int negtive  = 0;
		for(int m=-1;m<=1;m++)
		for(int n=-1;n<=1;n++)
		if(m!=0 || n!=0)
		{
			if(result[i+m][j+n]<-5)negtive++;
			if(result[i+m][j+n]>=5)positive++;
		}
		if(positive>2 && negtive>2) 
		{
			target[i][j].rgbBlue = target[i][j].rgbGreen = target[i][j].rgbRed = 0;
		}

	}

	if(result!=NULL)
	{
		for (int i=0 ;i<m_nWndHeight;i++)
			if(result[i]!=NULL) delete result[i];
		delete result;
	}
}

////////////////////////////////////////////////////////////////////////////////
// 二值化
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::OnBtnBinary() 
{
	SetCursor(LoadCursor(NULL,IDC_WAIT));
	
	if(!method1->CalBinary())
	{
		AfxMessageBox("请先计算相似度!");
		SetCursor(LoadCursor(NULL,IDC_ARROW));	
		return;
	}
	
	m_bShowFace = false;
	for(int i=0; i<m_nWndHeight; i++)
	for(int j=0; j<m_nWndWidth;  j++)
	{
		m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	
		m_tResPixelArray[i][j].rgbRed  = (int)(method1->m_pBinaryArray[i][j]*255);
	}
	MakeBitMap();
	SetCursor(LoadCursor(NULL,IDC_ARROW));	
	MyDraw();
}

////////////////////////////////////////////////////////////////////////////////
// 边缘提取
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::OnBtnEdge() 
{
	if(!m_bFaceOK)
	{
		AfxMessageBox("请先确定脸部区域");
		return;
	}
	//左右眼的水平区域
	int nLeft,nRight,nTop,nBottom;

	nLeft	= m_rFaceRegion.left-5  > 0 ? m_rFaceRegion.left-5:0;
	nRight	= m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1;
	nTop	= m_rFaceRegion.top-5   > 0 ? m_rFaceRegion.top-5:0;
	nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1;
	//边缘检查
	DoLOG(nLeft,nRight,nTop,nBottom,m_tOriPixelArray,m_tResPixelArray);
	MakeBitMap();	
}

////////////////////////////////////////////////////////////////////////////////
// 求取头发和脸部区域
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::OnBtnFacehair() 
{
	m_bShowFace = false;
	SetCursor(LoadCursor(NULL,IDC_WAIT));
	method2->MarkHairFace();
	for(int i=0; i<m_nWndHeight; i++)
	for(int j=0; j<m_nWndWidth;  j++)
	{
		switch(method2->m_pBinaryArray[i][j])
		{
		case 0:
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	0;
			m_tResPixelArray[i][j].rgbRed  = 255;
			break;
		case 1:
			m_tResPixelArray[i][j].rgbBlue = 255;
			m_tResPixelArray[i][j].rgbGreen=m_tResPixelArray[i][j].rgbRed=0;
			break;
		case 2:
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	
			m_tResPixelArray[i][j].rgbRed  = 0;
			break;
		}
	}
	MakeBitMap();
	SetCursor(LoadCursor(NULL,IDC_ARROW));	
}

////////////////////////////////////////////////////////////////////////////////
// 脸部区域直方图
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::OnBtnHistogramFace() 
{
	if(!method2->m_bBinaryOK)
	{
		AfxMessageBox("请先计算二值化图!");
		return;
	}

	m_bShowFace = false;
	SetCursor(LoadCursor(NULL,IDC_WAIT));
	for(int j=0; j<m_nWndWidth;  j++)	
	{
		int count = 0;
		for(int i=0; i<m_nWndHeight; i++)
		{
			if(method2->m_pBinaryArray[i][j] == 0) count++;
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	
			m_tResPixelArray[i][j].rgbRed  = 255;
		}
		for(i=m_nWndHeight-1; i>=m_nWndHeight-count;i--)
		{
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	
			m_tResPixelArray[i][j].rgbRed  = 0;
		}
	}

	MakeBitMap();
	SetCursor(LoadCursor(NULL,IDC_ARROW));			
}

////////////////////////////////////////////////////////////////////////////////
// 水平方向直方图
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::OnBtnHistogramH() 
{
	if(!method1->m_bBinaryReady)
	{
		AfxMessageBox("请先计算二值图");
		return;
	}
	m_bShowFace = false;
	SetCursor(LoadCursor(NULL,IDC_WAIT));
	for(int j=0; j<m_nWndWidth;  j++)	
	{
		int count = 0;
		for(int i=0; i<m_nWndHeight; i++)
		{
			if(method1->m_pBinaryArray[i][j] == 1) count++;
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	
			m_tResPixelArray[i][j].rgbRed  = 255;
		}
		for(i=m_nWndHeight-1; i>=m_nWndHeight-count;i--)
		{
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	
			m_tResPixelArray[i][j].rgbRed  = 0;
		}
	}
	MakeBitMap();
	SetCursor(LoadCursor(NULL,IDC_ARROW));		
}

////////////////////////////////////////////////////////////////////////////////
// 头发的直方图
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::OnBtnHistogramHair() 
{
	if(!method2->m_bBinaryOK)
	{
		AfxMessageBox("请先计算二值图!");
		return;
	}
	m_bShowFace = false;
	SetCursor(LoadCursor(NULL,IDC_WAIT));
	for(int j=0; j<m_nWndWidth;  j++)	
	{
		int count = 0;
		for(int i=0; i<m_nWndHeight; i++)
		{
			if(method2->m_pBinaryArray[i][j] == 1) count++;
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	
			m_tResPixelArray[i][j].rgbRed  = 255;
		}
		for(i=m_nWndHeight-1; i>=m_nWndHeight-count;i--)
		{
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	
			m_tResPixelArray[i][j].rgbRed  = 0;
		}
	}
	MakeBitMap();
	SetCursor(LoadCursor(NULL,IDC_ARROW));					
}

////////////////////////////////////////////////////////////////////////////////
// 垂直方向的直方图
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::OnBtnHistogramV() 
{
	if(!method1->m_bBinaryReady)
	{
		AfxMessageBox("请先计算二值图");
		return;
	}

	m_bShowFace = false;
	SetCursor(LoadCursor(NULL,IDC_WAIT));
	for(int i=0; i<m_nWndHeight; i++)		
	{
		int count = 0;
		for(int j=0; j<m_nWndWidth;  j++)
		{
			if(method1->m_pBinaryArray[i][j] == 1) count++;
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	
			m_tResPixelArray[i][j].rgbRed  = 255;
		}
		for(j=0; j<count;  j++)
		{
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	
			m_tResPixelArray[i][j].rgbRed  = 0;
		}
	}
	MakeBitMap();
	SetCursor(LoadCursor(NULL,IDC_ARROW));			
}

////////////////////////////////////////////////////////////////////////////////
// 计算相似度
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::OnBtnLikehood() 
{
	m_bShowFace = false;
	SetCursor(LoadCursor(NULL,IDC_WAIT));

	method1->CalLikeHood();
	for(int i=0; i<m_nWndHeight; i++)
	for(int j=0; j<m_nWndWidth;  j++)
	{
		m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	
		m_tResPixelArray[i][j].rgbRed  = (int)(method1->m_pLikeliHoodArray[i][j]*255);
	}
	MakeBitMap();

	SetCursor(LoadCursor(NULL,IDC_ARROW));	
}

////////////////////////////////////////////////////////////////////////////////
// 标记眼睛区域
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::OnBtnMarkEye() 
{
	int i,j;
	if(!m_bFaceOK)
	{
		AfxMessageBox("请先确定脸部区域");
		return;
	}
	//左右眼的水平区域
	CPoint LeftEyeAreaH(-1,-1),RightEyeAreaH(-1,-1);
	CPoint LeftEyeAreaV(-1,-1),RightEyeAreaV(-1,-1);

	int nLeft,nRight,nTop,nBottom;

	nLeft	= m_rFaceRegion.left-5  > 0 ? m_rFaceRegion.left-5:0;
	nRight	= m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1;
	nTop	= m_rFaceRegion.top-5   > 0 ? m_rFaceRegion.top-5:0;
	nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1;
	//边缘检查
	DoLOG(nLeft,nRight,nTop,nBottom,m_tOriPixelArray,m_tResPixelArray);

	///////////////////////////////////
	//确认两个眼睛的水平区域
    //////////////////////////////////
	int nSlidWinWidth  = (m_rFaceRegion.right - m_rFaceRegion.left)/6/2;
	int nSlidWinHeight = (m_rFaceRegion.bottom - m_rFaceRegion.top)/15/2;
	int nMidFaceH = (m_rFaceRegion.right+m_rFaceRegion.left)/2;
	int nMidFaceV = (m_rFaceRegion.bottom+m_rFaceRegion.top)/2;

	int *tempArray = new int[m_nWndWidth]; 
	for(i = 0; i<m_nWndWidth; i++) tempArray[i] = 0;

	for(i=nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--)
	for(j=m_rFaceRegion.left+nSlidWinWidth; j<m_rFaceRegion.right-nSlidWinWidth; j++)
	{
		int count = 0;
		for(int p= -nSlidWinHeight ;p<nSlidWinHeight;p++)
		for(int q= -nSlidWinWidth ;q<nSlidWinWidth;q++)
		{
			if(m_tResPixelArray[i+p][j+q].rgbRed == 0)	count++;
		}
		if(count >= nSlidWinWidth*nSlidWinHeight/3)
		{
			m_tResPixelArray[i][j].rgbRed = 255;
			tempArray[j] ++;
		}
	}

	MakeBitMap();
	AfxMessageBox("眼睛的区域鉴别");

	CList<CPoint,CPoint&> myList1(sizeof(CPoint));
	CList<CPoint,CPoint&> myList2(sizeof(CPoint));
	int flag = 0;
	CPoint tPoint(-1,-1);
	for(i = 0; i<m_nWndWidth; i++)
	{
		if(tempArray[i] > 0 && flag ==0)
		{
			tPoint.x = i;
			flag = 1;
		}
		if(tempArray[i] == 0 && flag ==1)
		{
			tPoint.y = i;
			myList1.AddTail(tPoint);
			flag = 0;
		}
	}
	delete tempArray;
	//去掉长度太小的候选者	
	for(i=0; i<myList1.GetCount();i++)
	{
		CPoint temp(-1,-1);
		temp = myList1.GetAt(myList1.FindIndex(i));
		int minVal = (m_rFaceRegion.right - m_rFaceRegion.left)/20;
		if((temp.y-temp.x)>=minVal)
			myList2.AddTail(temp);
	}
	myList1.RemoveAll();
    //合并相邻很紧的区域
	bool quit = 1;
	while(quit)
	{
		bool doJoin = false;
		for(int i=0; i<myList2.GetCount()-1;i++)
		{
			CPoint temp1(-1,-1),temp2(-1,-1);
			temp1 = myList2.GetAt(myList2.FindIndex(i));
			temp2 = myList2.GetAt(myList2.FindIndex(i+1));
			if((temp2.x-temp1.y)<=(m_rFaceRegion.right - m_rFaceRegion.left)/40)
			{
				temp1.y = temp2.y;
				myList2.RemoveAt(myList2.FindIndex(i));
				myList2.RemoveAt(myList2.FindIndex(i));
				if(i == 0)			myList2.AddHead(temp1);
				else			    myList2.InsertAfter(myList2.FindIndex(i-1),temp1);
				doJoin = true;
				break;
			}	
		}
		if(!doJoin)	quit = 0;
	}

	//没有找到眼睛区域
	if(myList2.GetCount()<2) 
	{
		CPoint t=myList2.GetHead();
		if((t.y-t.x)>(m_rFaceRegion.right - m_rFaceRegion.left)/2)
		{
			LeftEyeAreaH.x = t.x; 
			LeftEyeAreaH.y = t.x+(t.y-t.x)/3; 
			RightEyeAreaH.x = t.y-(t.y-t.x)/3;
			RightEyeAreaH.y = t.y; 
		}
		else
		{
			AfxMessageBox("确认眼睛位置失败,请手动标定");
			return;
		}
	}
	//仅有两个区域
	else if(myList2.GetCount()==2)
	{
		LeftEyeAreaH = myList2.GetHead();
		RightEyeAreaH = myList2.GetTail();
	}
	else  //多于两个区域
	{
		int ldis = -100000;
		int rdis = 100000;	
		for(i=0; i<myList2.GetCount();i++)
		{
			CPoint temp(-1,-1);
			temp = myList2.GetAt(myList2.FindIndex(i));
			//右眼
			if((temp.x+temp.y)/2 > nMidFaceH)
			{
				if(((temp.x+temp.y)/2-nMidFaceH)<rdis)
				{
					rdis = (temp.x+temp.y)/2-nMidFaceH;
					RightEyeAreaH = temp;
				}
			}
			//左眼
			else
			{
				if(((temp.x+temp.y)/2-nMidFaceH)>ldis)
				{
					ldis = (temp.x+temp.y)/2-nMidFaceH;
					LeftEyeAreaH = temp;
				}
			}
		}
	}
	myList2.RemoveAll();
	///////////////////////////////////
	//确认两个眼睛的垂直区域
    //////////////////////////////////
	//左眼
	if(LeftEyeAreaH != CPoint(-1,-1))
	{
		int *tArray = new int[m_nWndHeight]; 
		int i,j;
		for(i = 0; i<m_nWndHeight; i++) tArray[i] = 0;

		for(i=nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--)
		for(j=LeftEyeAreaH.x; j<=LeftEyeAreaH.y;j++)
		if(m_tResPixelArray[i][j].rgbRed == 255 && m_tResPixelArray[i][j].rgbGreen == 0)
			tArray[i] ++;

		CList<CPoint,CPoint&> myListA(sizeof(CPoint));
		CList<CPoint,CPoint&> myListB(sizeof(CPoint));
		int flag = 0;
		CPoint tPoint(-1,-1);
		for(i = nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--)
		{
			if(tArray[i] > 0 && flag ==0)
			{
				tPoint.x = i;
				flag = 1;
			}
			if(tArray[i] == 0 && flag ==1)
			{
				tPoint.y = i;
				myListA.AddTail(tPoint);
				flag = 0;
			}
		}
		delete tArray;
		//去掉长度太小的候选者	
		for(i=0; i<myListA.GetCount();i++)
		{
			CPoint temp(-1,-1);
			temp = myListA.GetAt(myListA.FindIndex(i));
			int minVal = (m_rFaceRegion.bottom - m_rFaceRegion.top)/100;
			if((temp.x-temp.y)>=minVal)
				myListB.AddTail(temp);
		}
		myListA.RemoveAll();
		//合并相邻很紧的区域
		bool quit = 1;
		while(quit)
		{
			bool doJoin = false;
			for(int i=0; i<myListB.GetCount()-1;i++)
			{
				CPoint temp1(-1,-1),temp2(-1,-1);
				temp1 = myListB.GetAt(myListB.FindIndex(i));
				temp2 = myListB.GetAt(myListB.FindIndex(i+1));
				if((temp1.y-temp2.x)<=(m_rFaceRegion.bottom - m_rFaceRegion.top)/100)
				{
					temp1.y = temp2.y;
					myListB.RemoveAt(myListB.FindIndex(i));
					myListB.RemoveAt(myListB.FindIndex(i));
					if(i == 0)			myListB.AddHead(temp1);
					else			    myListB.InsertAfter(myListB.FindIndex(i-1),temp1);
					doJoin = true;
					break;
				}	
			}
			if(!doJoin)	quit = 0;
		}
		if(myListB.GetCount()==0)
		{
			AfxMessageBox("无法确定左眼的位置");
		}
		else
		{
			LeftEyeAreaV = myListB.GetHead();
			
			double sumX = 0.0;
			double sumY = 0.0;
			int sum = 0;
			m_LeftEyeLeftCorner.x = 100000;
			m_LeftEyeRightCorner.x = -1;

			for(i=LeftEyeAreaV.x; i>= LeftEyeAreaV.y;i--)
			for(j=LeftEyeAreaH.x; j<=LeftEyeAreaH.y;j++)
			if(m_tResPixelArray[i][j].rgbGreen == 0)
			{
				if(j<m_LeftEyeLeftCorner.x)	
				{
					m_LeftEyeLeftCorner.x = j;
					m_LeftEyeLeftCorner.y = i;
				}
				if(j>m_LeftEyeRightCorner.x)
				{
					m_LeftEyeRightCorner.x = j;
					m_LeftEyeRightCorner.y = i;
				}
				sumX += j;
				sumY += i;
				sum++;
			}

			m_LeftEye.x = (int)(sumX/sum);
			m_LeftEye.y = (int)(sumY/sum);	

			m_bLeftEyeOK = TRUE;	
			m_bLeftEyeLeftCornerOK = TRUE;
			m_bLeftEyeRightCornerOK =TRUE;
		}
		myListB.RemoveAll();
	}
	//右眼
	if(RightEyeAreaH != CPoint(-1,-1))
	{
		int *tArray = new int[m_nWndHeight]; 
		int i,j;
		for(i = 0; i<m_nWndHeight; i++) tArray[i] = 0;

		for(i=nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--)
		for(j=RightEyeAreaH.x; j<=RightEyeAreaH.y;j++)
		if(m_tResPixelArray[i][j].rgbRed == 255 && m_tResPixelArray[i][j].rgbGreen == 0)
			tArray[i] ++;

		CList<CPoint,CPoint&> myListA(sizeof(CPoint));
		CList<CPoint,CPoint&> myListB(sizeof(CPoint));
		int flag = 0;
		CPoint tPoint(-1,-1);
		for(i = nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--)
		{
			if(tArray[i] > 0 && flag ==0)
			{
				tPoint.x = i;
				flag = 1;
			}
			if(tArray[i] == 0 && flag ==1)
			{
				tPoint.y = i;
				myListA.AddTail(tPoint);
				flag = 0;
			}
		}
		delete tArray;
		//去掉长度太小的候选者	
		for(i=0; i<myListA.GetCount();i++)
		{
			CPoint temp(-1,-1);
			temp = myListA.GetAt(myListA.FindIndex(i));
			int minVal = (m_rFaceRegion.bottom - m_rFaceRegion.top)/100;
			if((temp.x-temp.y)>=minVal)
				myListB.AddTail(temp);
		}
		myListA.RemoveAll();
		//合并相邻很紧的区域
		bool quit = 1;
		while(quit)
		{
			bool doJoin = false;
			for(int i=0; i<myListB.GetCount()-1;i++)
			{
				CPoint temp1(-1,-1),temp2(-1,-1);
				temp1 = myListB.GetAt(myListB.FindIndex(i));
				temp2 = myListB.GetAt(myListB.FindIndex(i+1));
				if((temp1.y-temp2.x)<=(m_rFaceRegion.bottom - m_rFaceRegion.top)/50)
				{
					temp1.y = temp2.y;
					myListB.RemoveAt(myListB.FindIndex(i));
					myListB.RemoveAt(myListB.FindIndex(i));
					if(i == 0)			myListB.AddHead(temp1);
					else			    myListB.InsertAfter(myListB.FindIndex(i-1),temp1);
					doJoin = true;
					break;
				}	
			}
			if(!doJoin)	quit = 0;
		}
		if(myListB.GetCount()==0)
		{
			AfxMessageBox("无法确定右眼的位置");
		}
		else
		{
			if(myListB.GetCount()==1)
				RightEyeAreaV = myListB.GetHead();
			else
			{
				CPoint tt =  myListB.GetHead();
				int index = myListB.GetCount();
				while(tt.y > LeftEyeAreaV.x && index > 0)
				{
					index --;
					tt = myListB.GetAt(myListB.FindIndex(myListB.GetCount()-index)); 
				}
				RightEyeAreaV = tt;		
			}
			
			double sumX = 0.0;
			double sumY = 0.0;
			int sum = 0;
			m_RightEyeLeftCorner.x = 100000;
			m_RightEyeRightCorner.x = -1;

			for(i=RightEyeAreaV.x; i>=RightEyeAreaV.y;i--)
			for(j=RightEyeAreaH.x; j<=RightEyeAreaH.y;j++)
			if(m_tResPixelArray[i][j].rgbGreen == 0)
			{
				if(j<m_RightEyeLeftCorner.x)	
				{
					m_RightEyeLeftCorner.x = j;
					m_RightEyeLeftCorner.y = i;
				}
				if(j>m_RightEyeRightCorner.x)
				{
					m_RightEyeRightCorner.x = j;
					m_RightEyeRightCorner.y = i;
				}
				sumX += j;
				sumY += i;
				sum++;
			}
			m_RightEye.x = (int)(sumX/sum);
			m_RightEye.y = (int)(sumY/sum);
			
			m_bRightEyeOK = TRUE;
			m_bRightEyeLeftCornerOK = TRUE;
			m_bRightEyeRightCornerOK =TRUE;

		}
		myListB.RemoveAll();
	}
	CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
	MakeBitMap();		
}

////////////////////////////////////////////////////////////////////////////////
// 第一种方法标记脸部区域
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::OnBtnMarkFace1() 
{
	if(!method1->m_bBinaryReady)
	{
		AfxMessageBox("请先计算二值化图!");
		return;
	}
	m_bShowFace = true;
	SetCursor(LoadCursor(NULL,IDC_WAIT));
	int *temp = new int[m_nWndWidth];
	int max = 0;
	int pos = -1;
	for(int j=0; j<m_nWndWidth;  j++)	
	{
		int count = 0;
		for(int i=0; i<m_nWndHeight; i++)
		{
			if(method1->m_pBinaryArray[i][j] == 1) count++;
		}
		temp[j] = count;
		if(count > max)
		{
			max = count;
			pos = j;
		}
	}
	int left,right,l,top,bottom;
	for(l=pos; l>=0; l--)
	{
		if(temp[l]<max*0.2||l==0)
		{
			left = l;
			break;
		}
	}
	for(l=pos; l<m_nWndWidth; l++)
	{
		if(temp[l]<max*0.3||l==m_nWndWidth-1)
		{
			right = l;
			break;
		}
	}
	for(int i=0; i<m_nWndHeight; i++)
	{
		int count = 0;
		for(l = left;l<=right;l++)
		{
			if(method1->m_pBinaryArray[i][l] == 1) count++;
		}
		if(count>=(right-left)*0.5)
		{
			top = i;
			break;
		}
	}
	bottom = (int)(top+(right-left)*1.5)>=m_nWndHeight? m_nWndHeight-1:(int)(top+(right-left)*1.5);

	CopyBitMap(m_tResPixelArray,m_tOriPixelArray);

	for(i=top;i<=bottom;i++)
	{
		m_tResPixelArray[i][left].rgbBlue=255;
		m_tResPixelArray[i][left].rgbGreen = m_tResPixelArray[i][left].rgbRed = 0;
		m_tResPixelArray[i][right].rgbBlue=255;
		m_tResPixelArray[i][right].rgbGreen = m_tResPixelArray[i][right].rgbRed = 0;
	}
	for(j=left;j<=right;j++)
	{
		m_tResPixelArray[top][j].rgbBlue=255;
		m_tResPixelArray[top][j].rgbGreen = m_tResPixelArray[top][j].rgbRed = 0;
		m_tResPixelArray[bottom][j].rgbBlue=255;
		m_tResPixelArray[bottom][j].rgbGreen = m_tResPixelArray[bottom][j].rgbRed = 0;
	}
	MakeBitMap();
	SetCursor(LoadCursor(NULL,IDC_ARROW));			

	if(m_bFaceOK)
	{
		ReplaceDlg dlg;
		if(dlg.DoModal()==IDOK)
		{
			CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
			CRect rect(left,top,right,bottom);
			m_rFaceRegion = rect;
			MakeBitMap();
		}
	}
	else
	{
		m_bFaceOK = true;
		CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
		CRect rect(left,top,right,bottom);
		m_rFaceRegion = rect;
		MakeBitMap();
	}
}

////////////////////////////////////////////////////////////////////////////////
// 第二种方法标记脸部区域
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::OnBtnMarkFace2() 
{
	if(!method2->m_bBinaryOK)
	{
		AfxMessageBox("请先计算二值化图");
		return;
	}
	m_bShowFace = true;
	SetCursor(LoadCursor(NULL,IDC_WAIT));
	int *numR,*numB, i, j, left,right,top,bottom;
	int maxnumR = 0, maxnumB = 0;

	numR = new int[m_nWndWidth];
	numB = new int[m_nWndWidth];
	for(j=0;j<m_nWndWidth ;j++)
	{
		int countR = 0, countB = 0;
		for(i=0;i<m_nWndHeight;i++)
		{
			if(method2->m_pBinaryArray[i][j] == 0)
				countR++;
			if(method2->m_pBinaryArray[i][j] == 1)
				countB++;
		}
		if(countR > maxnumR) maxnumR = countR;
		numR[j] = countR;
		if(countB > maxnumB) maxnumB = countB;
		numB[j] = countB;
	}
	CList<CPoint,CPoint> myListR(sizeof(CPoint));
	CList<CPoint,CPoint> myListB(sizeof(CPoint));
	CPoint tempR,tempB;
	int flagR = 0,flagB = 0;
	for(j=0;j<m_nWndWidth ;j++)
	{
		if(flagR == 0)
		{
			if(numR[j]>maxnumR/2)
			{
				flagR = 1;
				tempR.x = j;				
			}
		}
		else
		{
			if(numR[j]<=maxnumR/2 || j==m_nWndWidth-1)
			{
				flagR = 0;
				tempR.y = j;
				myListR.AddTail(tempR);
			}
		}
		if(flagB == 0)
		{
			if(numB[j]>maxnumB/5)
			{
				flagB = 1;
				tempB.x = j;
			}
		}
		else
		{
			if(numB[j]<=maxnumB/5 || j==m_nWndWidth-1)
			{
				flagB = 0;
				tempB.y = j;
				if(myListB.GetCount() > 1 && (tempB.x-myListB.GetTail().y)<20)
					myListB.SetAt(myListB.GetTailPosition(),CPoint(myListB.GetTail().x,j));
				else
				myListB.AddTail(tempB);
			}
		}

	}	
	if(numR!=NULL)delete numR;
	if(numB!=NULL)delete numB;

	int *hairmark, k;
	hairmark = new int[m_nWndWidth];
	for(j=0;j<m_nWndWidth ;j++) hairmark[j]=0;

	for(k=0;k<myListB.GetCount();k++)
	{
		CPoint temp = myListB.GetAt(myListB.FindIndex(k));
		if((temp.y-temp.x)>m_nWndWidth/10)
		{
			for(int t = temp.x;t<=temp.y;t++)
			hairmark[t] = 1;
		}
	}

	for(k=0;k<myListR.GetCount();k++)
	{
		CPoint temp = myListR.GetAt(myListR.FindIndex(k));
		int templeft=-1;
		int tempright=-1;

		if((temp.y-temp.x)>m_nWndWidth/10)
		{
			for(int t=temp.x;t<=temp.y;t++)
			{
				if(hairmark[t]==1)
				{
					int endpos=t+(temp.y-temp.x)/5;
					if(endpos > temp.y)endpos = temp.y;
					int yes = 1;
					for(int q=t;q<=endpos;q++)
						if(hairmark[q]==0) yes = 0;
					if(yes == 1)
					{
						templeft = t;
						break;
					}
				}
			}
			for(int p=temp.y;p>=temp.x;p--)
			{
				if(hairmark[p]==1)
				{
					int beginpos=p-(temp.y-temp.x)/5;
					if(beginpos < temp.x)beginpos = temp.x;
					int yes = 1;
					for(int q=p;q>=beginpos;q--)
						if(hairmark[q]==0) yes = 0;
					if(yes == 1)
					{
						tempright = p;
						break;
					}
				}
			}
		}
		if(templeft!=-1 && tempright!=-1)
		{
			left = templeft;
			right = tempright;
			break;
		}
	}
	if(hairmark !=NULL) delete hairmark;
	myListR.RemoveAll();
	myListB.RemoveAll();

	if(left-m_nWndWidth/50>0) left-=(int)m_nWndWidth/50;
	else left = 0;
	if(right+m_nWndWidth/40>m_nWndWidth) right=m_nWndWidth-1;
	else right += m_nWndWidth/40;

	for(i=0; i<m_nWndHeight; i++)
	{
		int count = 0;
		for(int l = left;l<=right;l++)
		{
			if(method2->m_pBinaryArray[i][l] == 0) count++;
		}
		if(count>=(right-left)*0.5)
		{
			top = i;
			break;
		}
	}
	bottom = (int)(top+(right-left)*1.5)>=m_nWndHeight? m_nWndHeight-1:(int)(top+(right-left)*1.5);

	CopyBitMap(m_tResPixelArray,m_tOriPixelArray);

	for(i=top;i<=bottom;i++)
	{
		m_tResPixelArray[i][left].rgbBlue=255;
		m_tResPixelArray[i][left].rgbGreen = m_tResPixelArray[i][left].rgbRed = 0;
		m_tResPixelArray[i][right].rgbBlue=255;
		m_tResPixelArray[i][right].rgbGreen = m_tResPixelArray[i][right].rgbRed = 0;
	}
	for(j=left;j<=right;j++)
	{
		m_tResPixelArray[top][j].rgbBlue=255;
		m_tResPixelArray[top][j].rgbGreen = m_tResPixelArray[top][j].rgbRed = 0;
		m_tResPixelArray[bottom][j].rgbBlue=255;
		m_tResPixelArray[bottom][j].rgbGreen = m_tResPixelArray[bottom][j].rgbRed = 0;
	}
	MakeBitMap();
	SetCursor(LoadCursor(NULL,IDC_ARROW));			

	if(m_bFaceOK)
	{
		ReplaceDlg dlg;
		if(dlg.DoModal()==IDOK)
		{
			CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
			CRect rect(left,top,right,bottom);
			m_rFaceRegion = rect;
			MakeBitMap();
		}
	}
	else
	{
		m_bFaceOK = true;
		CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
		CRect rect(left,top,right,bottom);
		m_rFaceRegion = rect;
		MakeBitMap();
	}
}

////////////////////////////////////////////////////////////////////////////////
// 标记嘴巴
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::OnBtnMarkMouse() 
{
	int i,j;
	if(!(m_bLeftEyeOK&&m_bRightEyeOK))
	{
		AfxMessageBox("请先确定眼睛");
		return;
	}
	//左右眼的水平区域
	int nLeft,nRight,nTop,nBottom;

	nLeft	= m_rFaceRegion.left-5  > 0 ? m_rFaceRegion.left-5:0;
	nRight	= m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1;
	nTop	= m_rFaceRegion.top-5   > 0 ? m_rFaceRegion.top-5:0;
	nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1;

	SetPixelArray(m_tResPixelArray,0);
	for(i=nTop; i<=nBottom; i++)
	for(j=nLeft; j<=nRight; j++)
	{
		BYTE R,G,B;
		double temp,dlta;
		R = m_tOriPixelArray[i][j].rgbRed;
		G = m_tOriPixelArray[i][j].rgbGreen;
		B = m_tOriPixelArray[i][j].rgbBlue;
		if((R==G) && (G==B)) temp = 0;
		else temp = 0.5*(2*R-G-B)/sqrt((R-G)*(R-G)+(R-B)*(G-B));
		dlta = acos(temp);
		if(dlta < 0.2)
		{
			m_tResPixelArray[i][j].rgbRed = 255;  
		}
		else m_tResPixelArray[i][j].rgbRed = 0;
	}

	MakeBitMap();
	AfxMessageBox("嘴的肤色鉴定");
	//双目斜角
	double tanThta;
	if(m_RightEye.y == m_LeftEye.y) tanThta = 0;
	else tanThta = (m_RightEye.y - m_LeftEye.y)/(m_RightEye.x - m_LeftEye.x);
	//双目距离
	int EyesDis = (m_RightEye.x-m_LeftEye.x)*(m_RightEye.x-m_LeftEye.x);
	EyesDis += (m_RightEye.y-m_LeftEye.y)*(m_RightEye.y-m_LeftEye.y);
	EyesDis = (int)sqrt(EyesDis);
	//双目平均高度
	int EyeV    = (m_RightEye.y + m_LeftEye.y)/2;
	//可能的嘴的区域
	int MouthUp   = (EyeV+1.0*EyesDis) > nBottom ? nBottom:(int)(EyeV+1.0*EyesDis);
	int MouthDown = (EyeV+1.5*EyesDis) > nBottom ? nBottom:(int)(EyeV+1.5*EyesDis);


	int* Y_Arry = new int[MouthDown-MouthUp];
	for(i =0 ;i < MouthDown-MouthUp ;i++) Y_Arry[i] = 0;
	int* X_Arry = new int[EyesDis];
	for(i =0 ;i < EyesDis ;i++) X_Arry[i] = 0;
	for(i = MouthUp ; i < MouthDown; i++)
	for(j = m_LeftEye.x; j< m_RightEye.x; j++)
	{
		if(m_tResPixelArray[i][j].rgbRed == 255)
		{
			Y_Arry[i-MouthUp] ++;
			X_Arry[j-m_LeftEye.x] ++;
		}
	}
	
	int maxY = 0;
	for(i =0 ;i < MouthDown-MouthUp ;i++)
	{
		if(Y_Arry[i]>maxY)
		{
			maxY = Y_Arry[i];
			m_MidMouth.y =  i+MouthUp - (MouthDown-MouthUp)/10;
		}
	}
	m_LeftMouthCorner.y  =(int)(m_MidMouth.y - tanThta*EyesDis/2);
	m_RightMouthCorner.y =(int)(m_MidMouth.y + tanThta*EyesDis/2);
	for(i =0 ;i < EyesDis ;i++)
	{
		if(X_Arry[i]>0)
		{
			m_LeftMouthCorner.x = i+m_LeftEye.x;
			break;
		}
	}
	for(i = EyesDis -1; i >=0 ;i--)
	{
		if(X_Arry[i]>0)
		{
			m_RightMouthCorner.x = m_LeftEye.x+i;
			break;
		}
	}

	//唇中点较薄
	int min = 1000000;
	for(i = (int)(3*EyesDis/7+0.5) ; i <= (int)(4*EyesDis/7+0.5);i++)
	{
		if(X_Arry[i]<min)
		{
			min = X_Arry[i];
			m_MidMouth.x = m_LeftEye.x+i;
		}
	}
	m_MidMouth.x = (int)(m_MidMouth.x+(m_LeftEye.x+EyesDis/2))/2;

	m_bMidMouthOK = TRUE;
	m_bLeftMouthCornerOK = TRUE;
	m_bRightMouthCornerOK = TRUE;
	
	CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
	MakeBitMap();	
}

////////////////////////////////////////////////////////////////////////////////
// 标记鼻子
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::OnBtnMarkNose() 
{
	int i,j;
	if(!(m_bLeftEyeOK&&m_bRightEyeOK))
	{
		AfxMessageBox("请先确定眼睛");
		return;
	}
	//左右眼的水平区域
	int nLeft,nRight,nTop,nBottom;

	nLeft	= m_rFaceRegion.left-5  > 0 ? m_rFaceRegion.left-5:0;
	nRight	= m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1;
	nTop	= m_rFaceRegion.top-5   > 0 ? m_rFaceRegion.top-5:0;
	nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1;

	SetPixelArray(m_tResPixelArray,0);
	for(i=nTop; i<=nBottom; i++)
	for(j=nLeft; j<=nRight; j++)
	{
		double Y;
		Y = 0.30*m_tOriPixelArray[i][j].rgbRed+0.59*m_tOriPixelArray[i][j].rgbGreen
			+0.11*m_tOriPixelArray[i][j].rgbBlue;
		if(Y<100)
		{
			m_tResPixelArray[i][j].rgbRed = 255;  
		}
		else m_tResPixelArray[i][j].rgbRed = 0;
	}

	MakeBitMap();
	AfxMessageBox("鼻子的肤色鉴定");
	//双目斜角
	double tanThta;
	if(m_RightEye.y == m_LeftEye.y) tanThta = 0;
	else tanThta = (m_RightEye.y - m_LeftEye.y)/(m_RightEye.x - m_LeftEye.x);
	//双目距离
	int EyesDis = (m_RightEye.x-m_LeftEye.x)*(m_RightEye.x-m_LeftEye.x);
	EyesDis += (m_RightEye.y-m_LeftEye.y)*(m_RightEye.y-m_LeftEye.y);
	EyesDis = (int)sqrt(EyesDis);
	//双目平均高度
	int EyeV    = (m_RightEye.y + m_LeftEye.y)/2;
	//可能的鼻子的区域
	int NoseUp   = (EyeV+0.5*EyesDis) > nBottom ? nBottom:(int)(EyeV+0.5*EyesDis);
	int NoseDown = (EyeV+0.8*EyesDis) > nBottom ? nBottom:(int)(EyeV+0.8*EyesDis);

	int* Y_Arry = new int[NoseDown-NoseUp];
	for(i =0 ;i < NoseDown-NoseUp ;i++) Y_Arry[i] = 0;

	int* X_Arry = new int[EyesDis];
	for(i =0 ;i < EyesDis ;i++) X_Arry[i] = 0;

	for(i = NoseUp ; i < NoseDown; i++)
	for(j = m_LeftEye.x+EyesDis/5; j< m_RightEye.x-EyesDis/5; j++)
	{
		if(m_tResPixelArray[i][j].rgbRed == 255)
		{
			Y_Arry[i-NoseUp] ++;
			X_Arry[j-m_LeftEye.x] ++;
		}
	}
	
	int maxY = 0;
	for(i =0 ;i < NoseDown-NoseUp ;i++)
	{
		if(Y_Arry[i]>maxY)
		{
			maxY = Y_Arry[i];
			m_MidNose.y =  i+NoseUp;
		}
	}
	m_LeftNostril.y  =(int)(m_MidNose.y - tanThta*EyesDis/2);
	m_RightNostril.y =(int)(m_MidNose.y + tanThta*EyesDis/2);
	for(i =0 ;i < EyesDis ;i++)
	{
		if(X_Arry[i]>0)
		{
			m_LeftNostril.x = i+m_LeftEye.x;
			break;
		}
	}
	for(i = EyesDis-1; i >=0 ;i--)
	{
		if(X_Arry[i]>0)
		{
			m_RightNostril.x = i+m_LeftEye.x;
			break;
		}
	}
	//唇中点较薄
	int min = 1000000;
	for(i = (int)(EyesDis/3+0.5) ; i <= (int)(2*EyesDis/3+0.5);i++)
	{
		if(X_Arry[i]<min)
		{
			min = X_Arry[i];
			m_MidNose.x = m_LeftEye.x+i;
		}
	}
	m_MidNose.x = (m_MidNose.x+(m_LeftEye.x+EyesDis/2))/2;

	m_bMidNoseOK = TRUE;
	m_bLeftNostrilOK = TRUE;
	m_bRightNostrilOK = TRUE;
	
	CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
	MakeBitMap();		
}

////////////////////////////////////////////////////////////////////////////////
// 打开文件
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::OnBtnOpenfile() 
{
	CAddSampleDlg FileDlg(TRUE, "", NULL, 
		OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT, 
		"BMP人脸图像(*.bmp)|*.bmp|所有文件(*.*)|*.*||",
		AfxGetMainWnd());

	CString strFile;
	if (FileDlg.DoModal () != IDOK)
		return;

	POSITION pos = FileDlg.GetStartPosition();
	strFile = FileDlg.GetNextPathName(pos);
	m_pMainDib->Open(strFile);
	
	m_nWndWidth = m_pMainDib->GetWidth();
	m_nWndHeight= m_pMainDib->GetHeight();
	m_sFileName = strFile;

	m_rFaceRegion.left = m_rFaceRegion.right = m_rFaceRegion.top = m_rFaceRegion.bottom = 0;

	m_bLeftEyeOK = m_bRightEyeOK = m_bLeftNostrilOK = m_bRightNostrilOK =
	m_bLeftEyeLeftCornerOK = m_bLeftEyeRightCornerOK = m_bRightEyeLeftCornerOK = 
	m_bRightEyeRightCornerOK = m_bLeftMouthCornerOK = m_bRightMouthCornerOK = false;

	m_bMidMouthOK = m_bMidNoseOK = false;

	m_LeftEye = m_RightEye = m_LeftEyeLeftCorner = m_LeftEyeRightCorner = 
	m_LeftNostril = m_RightNostril = m_RightEyeLeftCorner = m_RightEyeRightCorner =
	m_LeftMouthCorner = m_RightMouthCorner = m_MidMouth = m_MidNose = CPoint(-1,-1);

	SetCursor(LoadCursor(NULL,IDC_WAIT));
	//获取像素的值
	LoadOriPixel(m_pMainDib);
	MakeBitMap();
	SetCursor(LoadCursor(NULL,IDC_ARROW));	
}

////////////////////////////////////////////////////////////////////////////////
// 画图
////////////////////////////////////////////////////////////////////////////////
void CFaceDetectDlg::MyDraw()
{
	CRect rc;
	pDCShow->GetWindow()->GetClientRect(&rc);
	pDCShow->Rectangle(&rc);
	CDC dc;
	CBitmap *pOldBitmap;
	dc.CreateCompatibleDC(pDCShow);
	pOldBitmap=dc.SelectObject(m_pResMap);
	pDCShow->StretchBlt(0,0,m_nWndWidth,m_nWndHeight,&dc,0,0,m_nWndWidth,m_nWndHeight,SRCCOPY);
	dc.SelectObject(pOldBitmap);
	dc.DeleteDC();
}